package com.ran.java_gobang.api;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.ran.java_gobang.game.request.MatchRequest;
import com.ran.java_gobang.game.response.MatchResponse;
import com.ran.java_gobang.game.Matcher;
import com.ran.java_gobang.game.OnlineUserManager;
import com.ran.java_gobang.model.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: ran
 * Date: 2025-08-28
 * Time: 19:37
 * 处理匹配中的 websocket 请求, 并返回响应
 */
@Component
@Slf4j
public class MatchAPI extends TextWebSocketHandler {

    private ObjectMapper objectMapper = new ObjectMapper();

    @Autowired
    private OnlineUserManager onlineUserManager;
    @Autowired
    private Matcher matcher;

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        //  玩家上线, 加入到 OnlineUserManager 中
        // 1. 先后去当前用户的信息(谁在游戏大厅建立的连接)
        // 之所以能拿到 getAttributes 是因为在注册 websocket 的时候, 加的.addInterceptors(new HttpSessionHandshakeInterceptor()),
        // 他把 HttpSession 的所有 Attribute 都拿到 websocket 中了
        // 所以可以把之前 HttpSession 存的 user 拿到了
        /*这里拿到的 user 也可能为null, 直接通过url跳过登录*/
        try {
            User user = (User) session.getAttributes().get("user");

            // 2. 判断当前用户是否已经登录在线了, 已经登录的不能继续登录
            if (onlineUserManager.getFromGameHall(user.getUserId()) != null || onlineUserManager.getFromGameRoom(user.getUserId()) != null) {
                // 当前用户已经登录, 需要告知客户端
                log.error("当前该用户多开, userName: " + user.getUserName());
                MatchResponse response = new MatchResponse();
                response.setOk(true);
                response.setReason("当前禁止多开!");
                response.setMessage("repeatConnection");
                session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
                //session.close(); // 关闭连接 , 直接关闭不太合理
                return;
            }

            // 3. 拿到信息, 把该玩家设置为在线
            onlineUserManager.enterGameHall(user.getUserId(), session);
            log.info("玩家: " + user.getUserName() + " 进入游戏大厅!");
        }catch (NullPointerException e) {
            log.error("[matchAPI]建立连接出现空指针异常, e: " + e);
            // 用户未登录, 要把这个信息返回去
            MatchResponse response = new MatchResponse();
            response.setOk(false);
            response.setReason("你没有登陆, 不能进行匹配功能!");
            // session.sendMessage 参数需要一个 websocket 类型,所以用 TextMessage 包装JSON字符串,包装成文本格式的 websocket 数据报
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
        }
    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        // 处理开始匹配停止停止匹配请求
        User user = (User) session.getAttributes().get("user");
        // 获取客户端给服务器发的数据
        String payload = message.getPayload();
        // 这个载荷是一个 JSON 格式的字符串, 要转化为对象, 这里转化为 MatchRequest 对象
        MatchRequest matchRequest = objectMapper.readValue(payload, MatchRequest.class);
        MatchResponse response = new MatchResponse();
        if (matchRequest.getMessage().equals("startMatch")) {
            // 进入匹配队列
            // TODO 先创建一个类表示匹配队列, 然后返回响应给客户端
            matcher.add(user);

            response.setOk(true);
            response.setMessage("startMatch");
        } else if (matchRequest.getMessage().equals("stopMatch")) {
            // 退出匹配
            // TODO 创建一个类表示匹配队列, 把用户从队列中移除, 移除成功返回响应给客户端

            matcher.remove(user);

            response.setOk(true);
            response.setMessage("stopMatch");
        }else {
            response.setOk(false);
            response.setReason("非法的匹配请求!");
        }
        // 把响应发回去
        String json = objectMapper.writeValueAsString(response);
        session.sendMessage(new TextMessage(json));
    }

    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        try {
            // 玩家异常下线, 从 OnlineUserManager 删除
            User user = (User) session.getAttributes().get("user");
            WebSocketSession tmpSesion = onlineUserManager.getFromGameHall(user.getUserId());
            if (tmpSesion == session) {
                onlineUserManager.exitGameHall(user.getUserId());
            }
            // 玩家正在匹配中掉线, websocket 断开, 需要移出队列
            matcher.remove(user);
        }catch (NullPointerException e) {
            log.error("[matchAPI]发送数据出现空指针异常,用户未登录, e: " + e);
            // 用户未登录, 要把这个信息返回去
//            MatchResponse response = new MatchResponse();
//            response.setOk(false);
//            response.setReason("你没有登陆, 不能进行匹配功能!");
//            // session.sendMessage 参数需要一个 websocket 类型,所以用 TextMessage 包装JSON字符串,包装成文本格式的 websocket 数据报
//            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
        }
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        try {
            // 玩家下线, 从 OnlineUserManager 删除
            User user = (User) session.getAttributes().get("user");
            // 防止不同客户端重复登录同一个账号, 判断连接结束后的客户端的 session 与 当前主动关闭客户端的session是否一致
            // 一致代表主动关闭, 不一致代表双开, 断开连接就可以不必从 map 删除
            WebSocketSession tmpSesion = onlineUserManager.getFromGameHall(user.getUserId());
            if (tmpSesion == session) {
                onlineUserManager.exitGameHall(user.getUserId());
            }
            // 玩家正在匹配中掉线, websocket 断开, 需要移出队列
            matcher.remove(user);
        }catch (NullPointerException e) {
            log.error("[matchAPI]连接关闭出现空指针异常, 当前用户未登录, e: " + e);
            // 用户未登录, 要把这个信息返回去
//            MatchResponse response = new MatchResponse();
//            response.setOk(false);
//            response.setReason("你没有登陆, 不能进行匹配功能!");
//            // session.sendMessage 参数需要一个 websocket 类型,所以用 TextMessage 包装JSON字符串,包装成文本格式的 websocket 数据报
//            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
        }
    }
}
